package service

import (
	"context"
	"encoding/json"
	"errors"
	"github.com/zeebo/errs"
	"go.uber.org/zap"
	"net"
	"onvif_server/api/setting"
	setting2 "onvif_server/internal/library/setting"
	"onvif_server/internal/repository"
	"onvif_server/internal/utils"
	"onvif_server/pkg/network"
	"onvif_server/pkg/version"
)

type SettingService interface {
	GetNetwork(ctx context.Context) (res *setting.GetNetworksRes, err error)
	SetNetwork(ctx context.Context, req *setting.SetNetworkReq) error
	GetStorage(ctx context.Context) (res *setting.StoreReq, err error)
	SetStorage(ctx context.Context, req *setting.StoreReq) error
	GetBox(ctx context.Context) (res *setting.BoxInfo, err error)
	SetBox(ctx context.Context, req *setting.BoxInfo) error
	StorageDrivers(ctx context.Context) []setting.StoreDriver

	DiscoveryHandle([]byte, net.Addr) ([]byte, error)
}

func NewSettingService(service *Service, subRepo repository.SubscriptionRepository) SettingService {
	return &settingService{
		Service: service,
		subRepo: subRepo,
	}
}

type settingService struct {
	subRepo repository.SubscriptionRepository
	*Service
}

func (s *settingService) GetNetwork(ctx context.Context) (res *setting.GetNetworksRes, err error) {
	res = &setting.GetNetworksRes{Interfaces: make([]setting.Network, 0)}
	ifcs := s.getNetInterfaces()
	for _, ifc := range ifcs.Interfaces {
		res.Interfaces = append(res.Interfaces, setting.Network{
			Name:    ifc.Name,
			Mode:    ifc.Mode,
			Ip:      ifc.IP,
			Mask:    ifc.Mask,
			Gateway: ifc.Gateway,
			Dns:     ifc.DNS,
		})
	}
	res.DefaultName = ifcs.Default
	return
}

func (s *settingService) SetNetwork(ctx context.Context, req *setting.SetNetworkReq) error {
	ifcs := network.GetNetInterfaces()
	exists := false
	//检查是否存在
	for i := range ifcs {
		if ifcs[i].Name == req.DefaultName {
			exists = true
			break
		}
	}
	if !exists {
		return errors.New("设置的默认网卡不存在")
	}
	_err := s.settingLib.Store(setting2.NetworkDefault, req.DefaultName)
	if _err != nil {
		s.log.Error("更新默认网卡失败", zap.String("name", req.DefaultName), zap.Error(_err))
		return _err
	}
	ifc := network.NetInterface{
		Name:    req.Network.Name,
		Mode:    req.Network.Mode,
		IP:      req.Network.Ip,
		Mask:    req.Network.Mask,
		Gateway: req.Network.Gateway,
		DNS:     req.Network.Dns,
	}
	return network.SetNetInterface(ifc)
}

func (s *settingService) GetStorage(ctx context.Context) (*setting.StoreReq, error) {
	storage := setting.StoreReq{}
	storage.Driver = s.settingLib.GetWithDefault(setting2.StorageDriver, "").(string)
	oss := s.settingLib.GetWithDefault(setting2.StorageOss, "").(string)
	if oss != "" {
		_ = json.Unmarshal([]byte(oss), &storage.Oss)
	}
	cos := s.settingLib.GetWithDefault(setting2.StorageCos, "").(string)
	if oss != "" {
		_ = json.Unmarshal([]byte(cos), &storage.Cos)
	}
	return &storage, nil
}

func (s *settingService) SetStorage(ctx context.Context, req *setting.StoreReq) error {
	ers := errs.Group{}
	ers.Add(s.settingLib.Store(setting2.StorageDriver, req.Driver))
	if req.Driver == "oss" {
		b, _ := json.Marshal(req.Oss)
		ers.Add(s.settingLib.Store(setting2.StorageOss, string(b)))
	}
	if req.Driver == "cos" {
		b, _ := json.Marshal(req.Cos)
		ers.Add(s.settingLib.Store(setting2.StorageCos, string(b)))
	}
	return ers.Err()
}
func (s *settingService) GetBox(ctx context.Context) (*setting.BoxInfo, error) {
	storage := setting.BoxInfo{}
	storage.Name = s.settingLib.GetWithDefault(setting2.BoxName, "").(string)
	storage.Location = s.settingLib.GetWithDefault(setting2.BoxLocation, "").(string)
	return &storage, nil
}

func (s *settingService) SetBox(ctx context.Context, req *setting.BoxInfo) error {
	return errs.Combine(s.settingLib.Store(setting2.BoxName, req.Name), s.settingLib.Store(setting2.BoxLocation, req.Name))
}

func (s *settingService) StorageDrivers(ctx context.Context) []setting.StoreDriver {
	return []setting.StoreDriver{
		{
			Driver: setting.Kv{
				Label: "阿里云",
				Value: "oss",
			},
			Fields: []setting.Kv{
				{
					Label: "AccessKey",
					Value: "access_key_id",
				},
				{
					Label: "AccessSecret",
					Value: "access_key_secret",
				},
				{
					Label: "存储桶名称",
					Value: "bucket",
				},
				{
					Label: "云存储域名",
					Value: "endpoint",
				},
				{
					Label: "访问地址",
					Value: "url",
				},
			},
		},
		{
			Driver: setting.Kv{
				Label: "腾讯云",
				Value: "cos",
			},
			Fields: []setting.Kv{
				{
					Label: "AccessKey",
					Value: "access_key_id",
				},
				{
					Label: "AccessSecret",
					Value: "access_key_secret",
				},
				{
					Label: "云存储域名",
					Value: "endpoint",
				},
				{
					Label: "访问地址",
					Value: "url",
				},
			},
		},
	}
}

func (s *settingService) DiscoveryHandle(msg []byte, src net.Addr) ([]byte, error) {
	if string(msg) != "find" {
		return nil, nil
	}
	var ip string
	var isSelf bool
	network.EachIpv4Interfaces(func(ifcName string, ipNet *net.IPNet) bool {
		if srcIp, ok := src.(*net.UDPAddr); ok {
			if srcIp.IP.String() == ipNet.IP.String() {
				isSelf = true
				return false
			} else if ipNet.Contains(srcIp.IP) {
				ip = ipNet.IP.String()
				return false
			}
		}
		return true
	})
	//本机发出的，不回应
	if isSelf {
		return nil, nil
	}
	ret := struct {
		Version  string `json:"version"`   //版本
		Name     string `json:"name"`      //名称
		Location string `json:"location"`  //名称
		DeviceId string `json:"device_id"` //设备id
		Ip       string `json:"ip"`        //ip地址
		Endpoint string `json:"endpoint"`  //入口地址
	}{
		Version:  version.Build.Version,
		Name:     s.settingLib.GetWithDefault(setting2.BoxName, "").(string),
		Location: s.settingLib.GetWithDefault(setting2.BoxLocation, "").(string),
		DeviceId: utils.GetDeviceNo(),
		Ip:       ip,
		Endpoint: s.getEndpoint(ip),
	}
	return json.Marshal(ret)
}
